package com.ykt.controller;

import com.alibaba.fastjson.TypeReference;
import com.jfinal.aop.Before;
import com.ykt.common.ValueConstants;
import com.ykt.common.constant.ParamNames;
import com.ykt.common.utils.Colls;
import com.ykt.common.utils.DateUtil;
import com.ykt.common.utils.JsonConverter;
import com.ykt.common.utils.ModelUtil;
import com.ykt.common.utils.StringUtil;
import com.ykt.common.utils.UB;
import com.ykt.common.utils.page.PageData;
import com.ykt.common.utils.page.PageParam;
import com.ykt.converter.OrderConvert;
import com.ykt.model.AgentFee;
import com.ykt.model.Community;
import com.ykt.model.Goods;
import com.ykt.model.GoodsUnit;
import com.ykt.model.Order;
import com.ykt.model.OrderItem;
import com.ykt.service.AgentFeeService;
import com.ykt.service.CommunityService;
import com.ykt.service.GoodsService;
import com.ykt.service.OrderService;
import com.ykt.service.RepeatSubmitService;
import com.ykt.validator.CommonValidator;
import com.ykt.validator.OrderValidator;
import com.ykt.vo.OrderVo;
import com.ykt.vo.ResultStatus;
import com.ykt.vo.ResultVo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户订单操作
 *
 * @author wing
 * @version 1.0.0
 */
public class OrderController extends BaseController {

    private AgentFeeService agentFeeService = enhance(AgentFeeService.class.getName(), AgentFeeService.class);
    private CommunityService communityService = enhance(CommunityService.class.getName(), CommunityService.class);
    private GoodsService goodsService = enhance(GoodsService.class.getName(), GoodsService.class);
    private OrderService orderService = enhance(OrderService.class.getName(), OrderService.class);
    private RepeatSubmitService repeatSubmitService = enhance(RepeatSubmitService.class.getName(), RepeatSubmitService.class);

    /**
     * 查询订单列表
     */
    @Before({CommonValidator.UserIdValidator.class, CommonValidator.OrderStatusValidator.class})
    public void find() {
        Integer userId = getParaToInt("userId", -1);
        String orderStatus = getPara("orderStatus");

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put(Order.user_id, userId);
        paramMap.put(Order.status, orderStatus);

        PageParam<Map<String, Object>> param = super.toPageParam(paramMap);
        PageData<Order> pd = orderService.pageFindByUserIdAndStatus(param);
        if (pd == null) {
            this.returnJson(ResultVo.failure());
            return;
        }
        this.returnJson(ResultVo.success(pd.convert(OrderConvert.convertOrderList(pd.getPageData()))));
    }

    /**
     * 查询子订单
     */
    public void findSub() {
        String orderPno = getPara("orderPno");
        List<Order> models = orderService.findByOrderPno(orderPno);
        if (models == null) {
            super.returnJson(ResultVo.success(null));
        } else {
            super.returnJson(ResultVo.success(OrderConvert.convertOrderList(models)));
        }
    }

    /**
     * 查询订单列表
     */
    @Before({CommonValidator.UserIdValidator.class})
    public void findService() {
        Integer userId = getParaToInt("userId", -1);
        String serviceStatus = getPara("serviceStatus");

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put(Order.user_id, userId);
        paramMap.put(Order.service_status, serviceStatus);

        PageParam<Map<String, Object>> param = super.toPageParam(paramMap);
        PageData<Order> pd = orderService.pageFindByUserIdAndServiceStatus(param);
        if (pd == null) {
            this.returnJson(ResultVo.failure());
            return;
        }
        this.returnJson(ResultVo.success(pd.convert(OrderConvert.convertOrderList(pd.getPageData()))));
    }
    /**
     * 订单详情
     */
    @Before(CommonValidator.OrderIdValidator.class)
    public void detail() {
        Integer orderId = getParaToInt("orderId");

        Order order = orderService.findById(orderId);
        OrderVo orderVo = OrderConvert.convert(order);

        List<OrderItem> orderItems = orderService.findOrderItems(orderId);
        if (orderVo != null) {
            orderVo.setGoods(OrderConvert.convertOderItemList(orderItems));
        }

        this.returnJson(ResultVo.success(orderVo));
    }


    private boolean validateVersionCode() {
        int versionCode = getParaToInt("versionCode", -1);
        return versionCode > -1;
    }

    /**
     * 创建订单
     */
    @Before(OrderValidator.class)
    public void create() {
        if (!validateVersionCode()) {
            this.returnJson(ResultVo.failure(null, "创建订单失败，请下载最新版本！"));
            return;
        }

        Map<Order, List<OrderItem>> orders = this.createSubOrders();
        if (Colls.isEmpty(orders)) {
            this.returnJson(ResultVo.failure());
            return;
        }

        List<Integer> orderIds = orderService.save(orders);
        if (orderIds == null || orderIds.size() != orders.size()) {
            this.returnJson(ResultVo.failure());
        } else {
            this.returnJson(ResultVo.success(orderIds));
        }
    }

    private Map<Order, List<OrderItem>> createSubOrders() {
        Date date = new Date();

        // 根据社区ID查询地址
        int communityId = UB.i(getPara(ParamNames.communityId));
        Community community = communityService.find(communityId);
        if (community == null) {
            returnJson(new ResultVo<>(null, ResultStatus.INSERT_FAILURE, "社区点不存在"));
            return null;
        }

        // 区分各商铺的商品列表
        String goods = getPara("goods");
        List<Map<String, Integer>> goodses = JsonConverter.parse(goods, new TypeReference<List<Map<String, Integer>>>() {
        });
        Map<Integer, List<OrderItem>> orderItemsMap = getOrderItemMap(goodses);
        if (Colls.isEmpty(orderItemsMap)) {
            return null;
        }

        // 创建保存订单的有序Map
        Map<Order, List<OrderItem>> orderMap = new LinkedHashMap<>(orderItemsMap.size());

        // 创建子订单和父订单列表
        int idx = 0;
        int shopId = 0;// 父订单商铺编号
        double amount = 0; // 订单总金额
        double payAmount = 0; // 订单支付总金额
        int buyType = UB.i(getPara("buyType"));// 若为议价购物则新订单状态为待商户确认

        String parentOrderNo = genOrderNo(shopId, communityId);
        for (Map.Entry<Integer, List<OrderItem>> itemsEntry : orderItemsMap.entrySet()) {

            String status = (buyType != 1) ? Order.Status.USER_UNPAYMENT.name() : Order.Status.MERCHANT_UNCONFIRMED.name();
            String subOrderNo = genOrderNo(itemsEntry.getKey(), communityId);
            double oneOrderAmount = this.getOrderAmount(itemsEntry.getValue());
            boolean singleOrderType = (orderItemsMap.size() == 1);

            Order model = new Order();
            model.set(Order.user_id, UB.i(getPara(ParamNames.userId)));
            model.set(Order.order_no, subOrderNo);
            // 依据订单数量设置父订单编号
            model.set(Order.order_pno, singleOrderType ? subOrderNo : parentOrderNo);
            // 设置为单个订单或子订单类型
            model.set(Order.order_type, singleOrderType ? Order.OrderType.SINGLE.name() : Order.OrderType.SON.name());
            model.set(Order.receipt_name, getPara(ParamNames.receiptName));
            model.set(Order.receipt_phone, getPara(ParamNames.receiptPhone));
            model.set(Order.shop_id, itemsEntry.getKey());
            // 计算各订单总金额和支付金额
            model.set(Order.amount, oneOrderAmount);
            model.set(Order.pay_amount, oneOrderAmount);
            // 依据订单数量计算订单代购费
            model.set(Order.agent_fee, singleOrderType ? defaultAgentFee(oneOrderAmount) : 0);
            model.set(Order.status, status);
            model.set(Order.address, getPara(ParamNames.address));
            model.set(Order.remarks, getPara(ParamNames.remarks));
            model.set(Order.delivery_time, getPara(ParamNames.deliveryTime));
            model.set(Order.community_id, community.getInt(Community.id));
            model.set(Order.community_name, community.getStr(Community.name));
            model.set(Order.community_address, community.getStr(Community.address));
            model.set(Order.community_contacts_name, community.getStr(Community.contacts_name));
            model.set(Order.community_contacts_phone, community.getStr(Community.contacts_phone));
            model.set(Order.created_time, date);
            model.set(Order.updated_time, date);
            orderMap.put(model, itemsEntry.getValue());

            amount += UB.d(model.get(Order.amount), 0);// 父订单总金额
            payAmount += UB.d(model.get(Order.pay_amount), 0); // 父订单总支付金额

            // 子订单数大于1个时，最后一次才创建父订单
            if (!singleOrderType && ++idx == orderItemsMap.size()) {
                Order pModel = new Order();
                pModel.set(Order.user_id, UB.i(getPara(ParamNames.userId)));
                pModel.set(Order.order_no, parentOrderNo);
                pModel.set(Order.order_pno, parentOrderNo);
                // 设置为父订单
                pModel.set(Order.order_type, Order.OrderType.PARENT.name());
                pModel.set(Order.receipt_name, getPara(ParamNames.receiptName));
                pModel.set(Order.receipt_phone, getPara(ParamNames.receiptPhone));
                pModel.set(Order.shop_id, shopId); // 父订单商铺编号写死
                pModel.set(Order.amount, amount);
                pModel.set(Order.pay_amount, payAmount);
                // 设置代购费用
                pModel.set(Order.agent_fee, this.defaultAgentFee(amount));
                pModel.set(Order.status, status);
                pModel.set(Order.address, getPara(ParamNames.address));
                pModel.set(Order.remarks, getPara(ParamNames.remarks));
                pModel.set(Order.delivery_time, getPara(ParamNames.deliveryTime));
                pModel.set(Order.community_id, community.getInt(Community.id));
                pModel.set(Order.community_name, community.getStr(Community.name));
                pModel.set(Order.community_address, community.getStr(Community.address));
                pModel.set(Order.community_contacts_name, community.getStr(Community.contacts_name));
                pModel.set(Order.community_contacts_phone, community.getStr(Community.contacts_phone));
                pModel.set(Order.created_time, date);
                pModel.set(Order.updated_time, date);

                orderMap.put(pModel, null); // 父订单没有订单项
            }
        }

        // 计算父子订单代购费额和支付金额
        idx = 0;
        double sumSubAgentFee = 0.0;
        for (Map.Entry<Order, List<OrderItem>> entry : orderMap.entrySet()) {
            Order model = entry.getKey();

            double allAgentFee = this.calcAllAgentFee(communityId, amount);
            double subAgentFee = this.calcSubAgentFee(communityId, amount, model.getDouble(Order.amount));
            sumSubAgentFee += subAgentFee;

            //子订单代购费和订单实付金额
            if (model.getStr(Order.order_type).equals(Order.OrderType.SON.name())) {
                if ((1 + idx++) == orderMap.entrySet().size()) {
                    model.set(Order.agent_fee, (allAgentFee - sumSubAgentFee));
                } else {
                    model.set(Order.agent_fee, subAgentFee);
                }
                model.set(Order.pay_amount, (model.getDouble(Order.pay_amount) + subAgentFee));

            } else {
                model.set(Order.pay_amount, (model.getDouble(Order.pay_amount) + allAgentFee));
            }
        }

        return orderMap;
    }

    // 获取订单项
    private Map<Integer, List<OrderItem>> getOrderItemMap(List<Map<String, Integer>> goodses) {
        Map<Integer, List<OrderItem>> itemsMap = new HashMap<>();

        for (Map<String, Integer> itemMap : goodses) {
            int shopId = itemMap.get(ParamNames.shopId);
            int goodsId = itemMap.get(ParamNames.goodsId);
            int goodsCount = itemMap.get(ParamNames.count);

            if (!itemsMap.containsKey(shopId)) {
                itemsMap.put(shopId, new ArrayList<OrderItem>());
            }

            Goods model = goodsService.findByGoodsId(goodsId);
            OrderItem item = new OrderItem();
            item.set(OrderItem.goods_id, goodsId);
            item.set(OrderItem.goods_no, model.get(Goods.goods_no));
            item.set(OrderItem.goods_name, model.get(Goods.name));
            item.set(OrderItem.goods_count, goodsCount);
            item.set(OrderItem.goods_unit, model.getStr(ParamNames.unitName));
            item.set(OrderItem.goods_pcs, model.get(GoodsUnit.pcs));
            item.set(OrderItem.goods_price, model.get(Goods.sale_price));
            item.set(OrderItem.goods_amount, goodsCount * ModelUtil.d(model, Goods.sale_price)); // 每个商品的总价

            itemsMap.get(shopId).add(item);
        }

        return itemsMap;
    }

    private double getOrderAmount(List<OrderItem> orderItems) {
        double amount = 0;
        for (OrderItem orderItem : orderItems) {
            amount += UB.d(orderItem.get(OrderItem.goods_amount));
        }
        return amount;
    }

    // 生成订单编号，父订单编号的shopId为0
    private String genOrderNo(int shopId, int communityId) {
        return StringUtil.lpad(5, shopId) + StringUtil.lpad(5, communityId)
                + DateUtil.ymd1(new Date()) + StringUtil.randomStr(true, 4);
    }


    // 默认代购费算法
    private double defaultAgentFee(double allOrderAmount) {
        if (allOrderAmount >= 80) {
            return 3d;
        } else {
            return 5d;
        }
    }

    // 计算代购费
    private double calcAllAgentFee(int communityId, double allOrderAmount) {
        List<AgentFee> agentFees = agentFeeService.findByCommunityId(communityId);
        if (Colls.isEmpty(agentFees)) {
            // 默认的代购费用
            return defaultAgentFee(allOrderAmount);
        }

        for (AgentFee agentFee : agentFees) {
            double b = ModelUtil.d(agentFee, AgentFee.begin);
            double e = ModelUtil.d(agentFee, AgentFee.end);
            double f = ModelUtil.d(agentFee, AgentFee.fee);

            if (b <= allOrderAmount && allOrderAmount < e) {
                return f;
            }
        }

        return defaultAgentFee(allOrderAmount);
    }

    // 计算子订单代购费
    private double calcSubAgentFee(int communityId, double allOrderAmount, double oneOrderAmount) {
        double allAgentFee = calcAllAgentFee(communityId, allOrderAmount);
        double subAgentFee = 0d;

        //根据公式计算子订单代购费
        if (allOrderAmount > 0) {
            double fee = (oneOrderAmount / allOrderAmount) * allAgentFee;
            BigDecimal b = new BigDecimal(fee);
            subAgentFee = b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        }

        return subAgentFee;
    }

    /**
     * 订单状态修改：
     * 待商户确认:MERCHANT_UNCONFIRMED
     * 待用户支付:USER_UNPAYMENT
     * 待商户发货:MERCHANT_UNDELIVERY
     * 待用户收货:USER_UNRECEIPT
     * 完成:COMPLETED
     * CANCEL 取消
     * MERCHANT_RETURN 已退款
     */
    @Before({CommonValidator.OrderIdValidator.class, CommonValidator.OrderStatusValidator.class})
    public void modifyStatus() {
        Integer orderId = getParaToInt("orderId", -1);
        String orderStatus = getPara("orderStatus");

        orderService.updateStatus(orderId, orderStatus);

        returnJson(ResultVo.success());
    }

    /**
     * 用户轮询订单是否已被商户确认
     */
    @Before(CommonValidator.OrderIdValidator.class)
    public void polling() {
        Integer orderId = getParaToInt("orderId", -1);

        Order order = orderService.findById(orderId);

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("orderStatus", order.getStr("status"));

        returnJson(ResultVo.success(resultMap));
    }

    /**
     * 下发token，防止订单重复提交
     */
    public void token() {
        String token = repeatSubmitService.getToken(ValueConstants.PRS_BIZ_ORDER);
        this.returnJson(token);
    }
}
